package com.shareloke.server.netty.server

import com.shareloke.server.handler.MyWebSocketServerHandler
import com.shareloke.server.handler.MyWebsocketConnectHandler
import com.shareloke.server.netty.constant.NettyConst.WEBSOCKET_PATH
import io.netty.bootstrap.ServerBootstrap
import io.netty.channel.ChannelInitializer
import io.netty.channel.ChannelOption
import io.netty.channel.nio.NioEventLoopGroup
import io.netty.channel.socket.SocketChannel
import io.netty.channel.socket.nio.NioServerSocketChannel
import io.netty.handler.codec.http.HttpObjectAggregator
import io.netty.handler.codec.http.HttpServerCodec
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler
import io.netty.handler.stream.ChunkedWriteHandler
import java.net.InetSocketAddress

/**
 *
 *  描述：
 * Netty Reactor模型 -
 * 1.单线程模型:一个用户一个线程来处理，线程有极限
 * 2.多线程模型：加入线程池,线程池线程轮询执行任务
 * 3.主从多线程模型：俩个线程池，一个线程池接收请求，一个线程池处理IO（推荐，适用高并发环境）
 *
 *
 * @author wlp
 * @version 1.0.0
 * @date 2021/7/11 下午 01:32
 */
data class MyNettyServer(private val socketAddress: InetSocketAddress) {

    /**
     *
     *  方法描述：初始化
     *
     * @author wlp
     * @date 2021/7/11 下午 01:36
     */
    fun start() {
        //主线程池
        val mainGrp = NioEventLoopGroup()
        //从线程池
        val subGrp = NioEventLoopGroup()
        try {
            //1.创建netty服务器启动对象
            val serverBootstrap = ServerBootstrap()
            serverBootstrap.option(ChannelOption.SO_BACKLOG, 1024)
            //2.初始化
            serverBootstrap //指定使用的线程池
                .group(mainGrp, subGrp) // 绑定监听端口
                .localAddress(socketAddress) //指定netty通道类型
                .channel(NioServerSocketChannel::class.java) // 指定通道初始化器用来加载当Channel收到事件消息后，
                // 如何进行业务处理
                .childHandler(object : ChannelInitializer<SocketChannel>() {
                    /**
                     *
                     *  方法描述：初始化通道 在这个方法中去加载对应的ChannelHandler
                     *
                     * @param socketChannel 通道
                     * @author wlp
                     * @date 2021/7/11 下午 01:41
                     */
                    @Throws(Exception::class)
                    override fun initChannel(socketChannel: SocketChannel) {

                        // 获取管道，将一个一个的ChannelHandler添加到管道中
                        val pipeline = socketChannel.pipeline()

                        // websocket协议本身是基于Http协议的,添加一个http的编解码器
                        pipeline.addLast(HttpServerCodec())
                        // 添加一个用于支持大数据流的支持
                        pipeline.addLast(ChunkedWriteHandler())
                        // 添加一个聚合器，这个聚合器主要是将HttpMessage聚合成FullHttpRequest/Response
                        pipeline.addLast(HttpObjectAggregator(1024 * 64))
                        // 需要指定接收请求的路由
                        pipeline.addLast(MyWebsocketConnectHandler())
                        // 必须使用以ws后缀结尾的url才能访问
                        pipeline.addLast(WebSocketServerProtocolHandler(WEBSOCKET_PATH, null, true))
                        // 添加自定义的消息处理Handler
                        pipeline.addLast(MyWebSocketServerHandler())

                        // 增加心跳事件支持
                        // 第一个参数:  读空闲4秒
                        // 第二个参数： 写空闲8秒
                        // 第三个参数： 读写空闲60秒
                        // pipeline.addLast(new IdleStateHandler(4, 8, 60));
                        // pipeline.addLast(new MyNettySocketHearBeatHandler());
                    }
                })
            //3.服务器异步创建绑定
            val future = serverBootstrap.bind().sync()
            println("NettyWebSocketServer ---------> 启动正在监听： $socketAddress")
            //4.等待服务关闭
            future.channel().closeFuture().sync()
        } catch (e: Exception) {
            e.printStackTrace()
            println("netty websocket server 启动失败 --》{}${e.message}")
        } finally {
            //5.等待关闭服务器最后关闭资源
            mainGrp.shutdownGracefully()
            subGrp.shutdownGracefully()
        }
    }

}